package org.shiro.config;

import cn.hutool.core.lang.Snowflake;
import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

import javax.annotation.Resource;

import static com.baomidou.mybatisplus.annotation.DbType.MYSQL;

/**
 * 系统相关配置文件
 *
 * @author LiKun
 * @date 2021/11/2 17:31
 */
@Configuration
@MapperScan("org.shiro.mapper")
@ComponentScan({"com.knife", "org.cleaver.spring"})
public class SystemConfiguration {
    @Resource
    private RedisConnectionFactory redisConnectionFactory;

    /**
     * 注册雪花算法实现类
     *
     * @return 雪花算法
     */
    @Bean
    public Snowflake snowflake() {
        return new Snowflake(1, 1);
    }

    /**
     * redis相关序列化工具类
     *
     * @return 序列化
     */
    @Bean
    public StringRedisSerializer stringRedisSerializer() {
        return new StringRedisSerializer();
    }

    /**
     * redis相关序列化工具类
     *
     * @return 序列化
     */
    @Bean
    public GenericToStringSerializer genericToStringSerializer() {
        return new GenericToStringSerializer(Object.class);
    }

    /**
     * redis相关序列化工具类
     *
     * @return 序列化类
     */
    @Bean
    public GenericFastJsonRedisSerializer genericFastJsonRedisSerializer() {
        return new GenericFastJsonRedisSerializer();
    }

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        return objectMapper;
    }

    /**
     * redis相关序列化工具类
     *
     * @return 序列化
     */
    @Bean
    @DependsOn("objectMapper")
    public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer(ObjectMapper objectMapper) {
        return new GenericJackson2JsonRedisSerializer(objectMapper);
    }

    /**
     * MyBatis-Plus分页插件
     *
     * @return 分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(MYSQL));
        return mybatisPlusInterceptor;
    }

    /**
     * Redis序列化相关配置
     *
     * @return RedisTemplate
     */
    @Bean
    public RedisTemplate redisTemplate(GenericJackson2JsonRedisSerializer genericSerializer, StringRedisSerializer stringSerializer) {
        RedisTemplate<Object, Object> template = new RedisTemplate();

        template.setKeySerializer(stringSerializer);
        template.setValueSerializer(genericSerializer);
        template.setHashKeySerializer(stringSerializer);
        template.setHashValueSerializer(genericSerializer);
        template.setConnectionFactory(redisConnectionFactory);

        return template;
    }

    /**
     * 解决前后端分离项目的跨域问题
     *
     * @return CorsWebFilter
     */
    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();

        corsConfiguration.addAllowedOrigin("*");                   //允许该IP的客户端访问
        corsConfiguration.addAllowedHeader("*");                   //允许客户端携带的请求头
        corsConfiguration.addAllowedMethod("*");                   //允许客户端访问的请求方式
        corsConfiguration.setAllowCredentials(true);               //是否允许请求带有验证信息
        corsConfiguration.addExposedHeader("Authorization");       //暴露的头部信息(可以添加多个)
        configurationSource.registerCorsConfiguration("/**", corsConfiguration);

        return new CorsWebFilter(configurationSource);
    }
}
